package com.thiswhyme.gateway.dynamic.service;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: 路由更新服务
 * @author: thiswhyme
 * @date: 2020/8/27
 */
@Slf4j
@Service
public class DynamicRouteService implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    private static final List<String> ROUTE_LIST = new ArrayList<>();

    /**
     * 刷新路由
     * @param config
     */
    public void refreshRoutes(String config) {
        log.info("refresh routes start, content: {}", config);
        clearRoute();
        try {
            List<RouteDefinition> routes = JSONObject.parseArray(config, RouteDefinition.class);
            for(RouteDefinition route: routes) {
                addRoute(route);
            }
            publisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        } catch (Exception e) {
            log.error("refresh routes fail", e);
        }
        log.info("refresh routes success");
    }

    /**
     * 新增路由
     * @param definition
     * @return
     */
    private Boolean addRoute(RouteDefinition definition) {
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            ROUTE_LIST.add(definition.getId());
        } catch (Exception e) {
            log.error("add route fail, routeDefinitionId: {}", definition.getId(), e);
        }
        return true;
    }

    /**
     * 清空路由
     * @return
     */
    private Boolean clearRoute() {
        for(String id: ROUTE_LIST) {
            try {
                routeDefinitionWriter.delete(Mono.just(id)).subscribe();
            } catch (Exception e) {
                log.warn("清除路由失败，路由可能已被清除，routeId：{}，errMsg：{}", id, e.getMessage(), e);
            }
        }
        ROUTE_LIST.clear();
        return true;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}
